home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / KeyPressManagerPanel.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  18.5 KB  |  742 lines

  1. package symantec.itools.awt;
  2.  
  3.  
  4. import java.awt.Button;
  5. import java.awt.Component;
  6. import java.awt.Container;
  7. import java.awt.Event;
  8. import java.awt.Label;
  9. import java.awt.Panel;
  10. import java.awt.TextComponent;
  11. import java.util.Vector;
  12.  
  13.  
  14. /**
  15.  * A Panel extension which provides for
  16.  * tabbing between components and supporting certain key accelerations
  17.  * by posting events provided by the user. Can be used directly or extended.
  18.  * When extending from BaseTabbedPanel be sure to super()
  19.  * during construction and to super.handleEvent(evt) from
  20.  * handleEvent if you override it.
  21.  * <p>
  22.  * The tab focus order is based on the order in which the components were 
  23.  * positioned within the selected layout manager. Each component receives 
  24.  * focus in turn, but the mouse cursor is not relocated. Look at the Project 
  25.  * window to see the tab order of components within the KeyPressManagerPanel. 
  26.  * You can change the tab order by moving the component names in the Project 
  27.  * window list.
  28.  * <p>
  29.  * Components respond to default events when they receive focus. For example,
  30.  * the TextField component displays text input from the keyboard, and the 
  31.  * Button component issues an action event when it is clicked.
  32.  * <p>
  33.  * Use KeyPressManagerPanel to create a panel whose elements can be tabbed 
  34.  * through, and specifically to:
  35.  * <UL>
  36.  * <DT>╖ create a subcontainer that organizes container space within an Applet,
  37.  * Frame or Dialog container. This simplifies your component layout task.</DT>
  38.  * <DT>╖ hold other specialized Panel containers.</DT>
  39.  * </UL>
  40.  * @version 1.0, Nov 26, 1996
  41.  * @author Symantec
  42.  */
  43.  
  44. //  05/15/97    CAR Changed doTab to "deselect" the text of the text component being tabbed from
  45. //     03/03/97    RKM    Fixed a bug in doTab, where it would tab to a hidden component
  46. //     03/13/97    RKM    Added code in HandleEvent to handle return being hit in TextFields which
  47. //                    results in a Action being sent
  48. //     03/13/97    RKM    Added ability to tab to TextComponents only, and defaulted it true for Mac
  49. //                    On platforms that support tabbing this is not needed, but on the Mac tabbing
  50. //                    would stop if you hit anything but a TextComponent - this seems a descent solution
  51. //
  52. //                    When encountering a non TextComponent on the Mac before defaulting to true:
  53. //                        Netscape - would not tab to the next component
  54. //                        Symantec - focus would be lost
  55. //                        Apple - tabbing works, but no focus is shown in non TextComponents and keys do nothing (ie List)
  56. //                        MW - same as Apple
  57.  
  58. public class KeyPressManagerPanel
  59.     extends Panel
  60. {
  61.     //--------------------------------------------------
  62.     // constants
  63.     //--------------------------------------------------
  64.  
  65.     /**
  66.      * A constant that indicates no modifier keys (SHIFT,CTRL) were pressed with a key.
  67.      */
  68.     public static final int PLAIN = 0;
  69.     /**
  70.      * A constant that indicates SHIFT was pressed with a key.
  71.      */
  72.     public static final int SHIFT = Event.SHIFT_MASK;
  73.     /**
  74.      * A constant that indicates CTRL was pressed with a key.
  75.      */
  76.     public static final int CTRL = Event.CTRL_MASK;
  77.  
  78.  
  79.     //--------------------------------------------------
  80.     // class variables
  81.     //--------------------------------------------------
  82.  
  83.  
  84.     //--------------------------------------------------
  85.     // member variables
  86.     //--------------------------------------------------
  87.  
  88.     Vector tabbed;
  89.     Button defaultButton;
  90.     Button cancelButton;
  91.     Event defaultEvent;
  92.     Event cancelEvent;
  93.     Event fKeyEvents[];
  94.     Container defaultDeliver;
  95.     Container cancelDeliver;
  96.     Container fKeyDeliver[];
  97.     boolean bDefaultSetFocus;
  98.     boolean bCancelSetFocus;
  99.     boolean bTabHack;
  100.     boolean bAutoTab;
  101.     boolean bOnlyTabToTextComponents;
  102.     Event eventLostFocus;
  103.  
  104.  
  105.     //--------------------------------------------------
  106.     // constructors
  107.     //--------------------------------------------------
  108.  
  109.     /**
  110.      * Constructs a Panel which handles key press events.
  111.      */
  112.     public KeyPressManagerPanel()
  113.     {
  114.         fKeyEvents  = new Event[36];
  115.         fKeyDeliver = new Container[36];
  116.         bAutoTab    = true;
  117.         if (symantec.itools.lang.OS.isMacintosh())
  118.             bOnlyTabToTextComponents = true;
  119.         else
  120.             bOnlyTabToTextComponents = false;
  121.         resetKeyManager();
  122.     }
  123.  
  124.  
  125.     //--------------------------------------------------
  126.     // accessor methods
  127.     //--------------------------------------------------
  128.  
  129.     /**
  130.      * Sets the automatic tab state. Note: this needs to be set before the
  131.      * add() method is called.
  132.      * @param bNewTabState new automatic tab state
  133.      * @see #getAutoTabState
  134.      * @see #add
  135.      */
  136.     public void setAutoTabState(boolean bNewTabState)
  137.     {
  138.         bAutoTab = bNewTabState;
  139.     }
  140.  
  141.     /**
  142.      * Gets the current automatic tab state.
  143.      * @return current automatic tab state value
  144.      * @see #setAutoTabState
  145.      */
  146.     public boolean getAutoTabState()
  147.     {
  148.         return bAutoTab;
  149.     }
  150.     
  151.     /**
  152.      * Sets whether tabs should only change focus to TextComponents.
  153.      * This is defaulted to true on a Macintosh
  154.      * @param bNewOnlyTabToTextComponents new tab to TextComponents only state
  155.      * @see #getTabToTextComponetsOnly
  156.      */
  157.     public void setTabToTextComponetsOnly(boolean bNewOnlyTabToTextComponents)
  158.     {
  159.         bOnlyTabToTextComponents = bNewOnlyTabToTextComponents;
  160.     }
  161.     
  162.     /**
  163.      * Gets whether tabbing is to TextComponents only.
  164.      * @return true if tabbing is to TextComponents only
  165.      * @see #setTabToTextComponetsOnly
  166.      */
  167.     public boolean getTabToTextComponetsOnly()
  168.     {
  169.         return bOnlyTabToTextComponents;
  170.     }
  171.     
  172.     //--------------------------------------------------
  173.     // event methods
  174.     //--------------------------------------------------
  175.     
  176.     /**
  177.      * Processes events for this component.
  178.      * This is a standard Java AWT method which gets called by the AWT
  179.      * to handle this component's events. The default handler for 
  180.      * components dispatches to one of the following methods as needed:
  181.      * action(), gotFocus(), lostFocus(), keyDown(), keyUp(), mouseEnter(),
  182.      * mouseExit(), mouseMove(), mouseDrag(), mouseDown(), or mouseUp().
  183.      *
  184.      * @param evt the event to handle
  185.      * @return true if the event was handled and no further action is needed,
  186.      * false to pass the event to this component's parent
  187.      * @see java.awt.Component#action
  188.      * @see java.awt.Component#gotFocus
  189.      * @see java.awt.Component#lostFocus
  190.      * @see java.awt.Component#keyDown
  191.      * @see java.awt.Component#keyUp
  192.      * @see java.awt.Component#mouseEnter
  193.      * @see java.awt.Component#mouseExit
  194.      * @see java.awt.Component#mouseMove
  195.      * @see java.awt.Component#mouseDrag
  196.      * @see java.awt.Component#mouseDown
  197.      * @see java.awt.Component#mouseUp
  198.      */
  199.     public synchronized boolean handleEvent(Event evt)
  200.     {
  201.         switch (evt.id)
  202.         {
  203.             case Event.ACTION_EVENT:
  204.                 //Has return been hit in a TextField
  205.                 if (evt.target instanceof java.awt.TextField)
  206.                 {
  207.                     //Make certain the TextField is in us (not one of our children)
  208.                     boolean itsOurs = false;
  209.                     int numChildren = countComponents();
  210.                     for (int i = 0;i< numChildren;i++)
  211.                     {
  212.                         Component testComponent = getComponent(i);
  213.                         if (testComponent != null && testComponent == evt.target)
  214.                         {
  215.                             itsOurs = true;
  216.                             break;
  217.                         }
  218.                     }
  219.                     
  220.                     if (itsOurs)
  221.                     {
  222.                         boolean buttonClicked = clickDefaultButton();
  223.                         if (buttonClicked)
  224.                             return true;
  225.                     }
  226.                 }
  227.                 break;
  228.             
  229.             case Event.KEY_ACTION:
  230.             {
  231.                 int index = evt.key - Event.F1;
  232.  
  233.                 switch (evt.modifiers)
  234.                 {
  235.                     case PLAIN:
  236.                     {
  237.                         break;
  238.                     }
  239.                     case SHIFT:
  240.                     {
  241.                         index += 12;
  242.                         break;
  243.                     }
  244.                     case CTRL:
  245.                     {
  246.                         index += 24;
  247.                         break;
  248.                     }
  249.                     default:
  250.                     {
  251.                         index = -1;
  252.                         break;
  253.                     }
  254.                 }
  255.  
  256.                 if ((index > -1) && (index < 36))
  257.                 {
  258.                     if (fKeyEvents[index] != null)
  259.                     {
  260.                         deliverEventTo(fKeyEvents[index], fKeyDeliver[index]);
  261.                         return true;
  262.                     }
  263.                 }
  264.  
  265.                 break;
  266.             }
  267.             case Event.KEY_PRESS:
  268.             {
  269.                 bTabHack = false;
  270.  
  271.                 if (keyPressed(evt))
  272.                 {
  273.                     return true;
  274.                 }
  275.  
  276.                 break;
  277.             }
  278.             case Event.LOST_FOCUS:
  279.             {
  280.                 if (evt.target instanceof TextComponent)
  281.                 {
  282.                     eventLostFocus = evt;
  283.                     bTabHack = true;
  284.                 }
  285.  
  286.                 break;
  287.             }
  288.             case Event.KEY_RELEASE:
  289.             {
  290.                 if (bTabHack)
  291.                 {
  292.                     bTabHack = false;
  293.                     eventLostFocus.key = evt.key;
  294.                     eventLostFocus.modifiers = evt.modifiers;
  295.  
  296.                     if (keyPressed(eventLostFocus))
  297.                     {
  298.                         return true;
  299.                     }
  300.                 }
  301.  
  302.                 break;
  303.             }
  304.         }//switch
  305.  
  306.         return super.handleEvent(evt);
  307.     }
  308.     
  309.     boolean clickDefaultButton()
  310.     {
  311.         if (defaultButton != null)
  312.         {
  313.             if (defaultButton.isEnabled())
  314.             {
  315.                 //???RKM??? Should we check if it is visible
  316.                 if (bDefaultSetFocus)
  317.                 {
  318.                     defaultButton.requestFocus();
  319.                 }
  320.                 
  321.                 deliverEventTo(defaultEvent, defaultDeliver);
  322.                 
  323.                 return true;
  324.             }
  325.         }
  326.         
  327.         return false;
  328.     }
  329.     
  330.     boolean keyPressed(Event evt)
  331.     {
  332.         switch (evt.key)
  333.         {
  334.             case 9: // TAB:
  335.             {
  336.                 if (evt.target instanceof Component)
  337.                 {
  338.                        return doTab((Component)evt.target, evt.modifiers);
  339.                    }
  340.  
  341.                 return doTab((Component) this, evt.modifiers); // component not in list
  342.             }
  343.             case 10: // ENTER:
  344.             {
  345.                 boolean buttonClicked = clickDefaultButton();
  346.                 if (buttonClicked)
  347.                     return true;
  348.                 break;
  349.             }
  350.             case 27: // ESC:
  351.             {
  352.                 if (cancelButton != null)
  353.                 {
  354.                     if (cancelButton.isEnabled())
  355.                     {
  356.                         if (bCancelSetFocus)
  357.                         {
  358.                             cancelButton.requestFocus();
  359.                         }
  360.  
  361.                         deliverEventTo(cancelEvent, cancelDeliver);
  362.  
  363.                         return true;
  364.                     }
  365.                 }
  366.  
  367.                 break;
  368.             }
  369.         }
  370.  
  371.         return false;
  372.     }
  373.  
  374.  
  375.     //--------------------------------------------------
  376.     // class methods
  377.     //--------------------------------------------------
  378.  
  379.  
  380.     //--------------------------------------------------
  381.     // memeber methods
  382.     //--------------------------------------------------
  383.  
  384.     /**
  385.      * Resets all KeyPressManager associations (default button, cancel
  386.      * button, tab stop list).
  387.      */
  388.     public void resetKeyManager()
  389.     {
  390.         tabbed           = new Vector();
  391.         defaultButton    = null;
  392.         cancelButton     = null;
  393.         defaultEvent     = null;
  394.         cancelEvent      = null;
  395.         defaultDeliver   = null;
  396.         cancelDeliver    = null;
  397.         bDefaultSetFocus = false;
  398.         bCancelSetFocus  = false;
  399.  
  400.         for (int x = 0; x < 36; x++)
  401.         {
  402.             fKeyEvents[x]  = null;
  403.             fKeyDeliver[x] = null;
  404.         }
  405.     }
  406.  
  407.     /**
  408.      * Adds a component to the end of this container.
  409.      * This is a standard Java AWT method which gets called to add a
  410.      * component to a container. The specified component is added to
  411.      * the end of this container.
  412.      * If auto-tab enabled (the default) 
  413.      * it also adds the component to the tab stop list.
  414.      * @param component the component to add
  415.      * @return the added component
  416.      * @see java.awt.Container#remove
  417.      */
  418.     public Component add(Component component)
  419.     {
  420.         if(bAutoTab)
  421.         {
  422.             if (!(component instanceof Label))
  423.             {
  424.                    setTabStop(component);
  425.                }
  426.         }
  427.  
  428.         return super.add(component);
  429.     }
  430.  
  431.     /**
  432.      * Removes Enter/Return key association with current default
  433.      * button/event.
  434.      * @see #setDefaultButton
  435.      */
  436.     public void removeDefaultButton()
  437.     {
  438.         defaultButton    = null;
  439.         defaultEvent     = null;
  440.         defaultDeliver   = null;
  441.         bDefaultSetFocus = false;
  442.     }
  443.  
  444.  
  445.     /**
  446.      * Sets the components as the next tab stop in the list
  447.      * components.
  448.      * @param component the Component
  449.      */
  450.     public void setTabStop(Component component)
  451.     {
  452.         if (component != this)
  453.         {
  454.             tabbed.addElement(component);
  455.         }
  456.     }
  457.  
  458.     /**
  459.      * Sets the button to press when the Enter or Return key
  460.      * is pressed.
  461.      * @param button the button to set as default
  462.      * @see #removeDefaultButton
  463.      */
  464.     public void setDefaultButton(Button button)
  465.     {
  466.         setDefaultButton(button, new Event(button, Event.ACTION_EVENT, null), null, true);
  467.     }
  468.  
  469.     /**
  470.      * Associates a button and event with the Enter or Return
  471.      * key press.
  472.      * @param button the button to set as default
  473.      * @param evt the event to delivered in response
  474.      * @param deliverTo the container to deliver the event to
  475.      * @param bSetFocus whether to set focus to the button before
  476.      * delivering event
  477.      * @see #removeDefaultButton
  478.      */
  479.     public void setDefaultButton(Button button, Event evt, Container deliverTo, boolean bSetFocus)
  480.     {
  481.         defaultButton    = button;
  482.         defaultEvent     = evt;
  483.         defaultDeliver   = deliverTo;
  484.         bDefaultSetFocus = bSetFocus;
  485.         button.requestFocus();
  486.     }
  487.  
  488.     /**
  489.      * Sets the button to press when the Escape key is pressed.
  490.      * @param button the button to set as Cancel
  491.      * @see #removeCancelButton
  492.      */
  493.     public void setCancelButton(Button button)
  494.     {
  495.         setCancelButton(button, new Event(button, Event.ACTION_EVENT, null), null, true);
  496.     }
  497.  
  498.     /**
  499.      * Associates a button and event with the Escape key press.
  500.      * @param button the button to set as Cancel
  501.      * @param evt the event to delivered in response
  502.      * @param deliverTo the container to deliver the event to
  503.      * @param bSetFocus whether to set focus to the button before
  504.      * delivering event
  505.      * @see #removeCancelButton
  506.      */
  507.     public void setCancelButton(Button button, Event evt, Container deliverTo, boolean bSetFocus)
  508.     {
  509.         cancelButton    = button;
  510.         cancelEvent     = evt;
  511.         bCancelSetFocus = bSetFocus;
  512.         cancelDeliver   = deliverTo;
  513.     }
  514.  
  515.     /**
  516.      * Removes Escape key association with current Cancel button/event
  517.      * @see #setCancelButton
  518.      */
  519.     public void removeCancelButton()
  520.     {
  521.         cancelButton    = null;
  522.         cancelEvent     = null;
  523.         cancelDeliver   = null;
  524.         bCancelSetFocus = false;
  525.     }
  526.  
  527.     /**
  528.      * Associates an event with a Function key press
  529.      * @param fKey the Event.F1 - Event.F12 constant
  530.      * @param evt the event to delivered in response
  531.      * @param deliverTo the container to deliver the event to
  532.      * @see #removeFKeyEvent
  533.      */
  534.     public void setFKeyEvent(int fKey, Event evt, Container deliverTo)
  535.     {
  536.         setFKeyEvent(fKey, PLAIN, evt, deliverTo);
  537.     }
  538.  
  539.     /**
  540.      * Removes association of an event with a Function key press
  541.      * @param fKey the Event.F1 - Event.F12 constant
  542.      * @see #setFKeyEvent
  543.      */
  544.     public void removeFKeyEvent(int fKey)
  545.     {
  546.         removeFKeyEvent(fKey, PLAIN);
  547.     }
  548.  
  549.     /**
  550.      * Associates an event with a Function key press
  551.      * @param fKey the Event.F1 - Event.F12 constant
  552.      * @param modifier PLAIN, SHIFT, or CTRL modifier
  553.      * @param evt the event to delivered in response
  554.      * @param deliverTo the container to deliver the event to
  555.      * @see #removeFKeyEvent
  556.      */
  557.     public void setFKeyEvent(int fKey, int modifier, Event evt, Container deliverTo)
  558.     {
  559.         int index = fKey - Event.F1;
  560.  
  561.         if ((index < 0) || (index > 11))
  562.         {
  563.             return;
  564.         }
  565.  
  566.         switch (modifier)
  567.         {
  568.             case PLAIN:
  569.             {
  570.                 break;
  571.             }
  572.             case SHIFT:
  573.             {
  574.                 index += 12;
  575.                 break;
  576.             }
  577.             case CTRL:
  578.             {
  579.                 index += 24;
  580.                 break;
  581.             }
  582.         }
  583.  
  584.         fKeyEvents[index] = evt;
  585.         fKeyDeliver[index] = deliverTo;
  586.     }
  587.  
  588.     /**
  589.      * Removes association of an event with a Function key press
  590.      * @param fKey the Event.F1 - Event.F12 constant
  591.      * @param modifier PLAIN, SHIFT, or CTRL modifier
  592.      * @see #setFKeyEvent
  593.      */
  594.     public void removeFKeyEvent(int fKey, int modifier)
  595.     {
  596.         int index = fKey - Event.F1;
  597.  
  598.         if ((index < 0) || (index > 11))
  599.         {
  600.             return;
  601.         }
  602.  
  603.         switch (modifier)
  604.         {
  605.             case PLAIN:
  606.             {
  607.                 break;
  608.             }
  609.             case SHIFT:
  610.             {
  611.                 index += 12;
  612.                 break;
  613.             }
  614.             case CTRL:
  615.             {
  616.                 index += 24;
  617.                 break;
  618.             }
  619.         }
  620.  
  621.         fKeyEvents[index] = null;
  622.         fKeyDeliver[index] = null;
  623.     }
  624.  
  625.     void deliverEventTo(Event evt, Container deliverTo)
  626.     {
  627.         if (deliverTo == null)
  628.         {
  629.             postEvent(evt);
  630.         }
  631.         else
  632.         {
  633.             deliverTo.postEvent(evt);
  634.         }
  635.     }
  636.  
  637.     boolean doTab(Component current, int tabModifiers)
  638.     {
  639.         int sze = tabbed.size();
  640.  
  641.         if (sze > 0 && (tabModifiers == 0 || tabModifiers == Event.SHIFT_MASK) )
  642.         {
  643.             Component tabTo = null;
  644.             int idx         = tabbed.indexOf(current);
  645.             int iCurrent    = idx;
  646.  
  647.             if (idx == -1)
  648.             {
  649.                 Component c = current;
  650.  
  651.                 while (c != this && idx == -1)
  652.                 {
  653.                     idx = tabbed.indexOf(c);
  654.                     c = c.getParent();
  655.                 }
  656.             }
  657.  
  658.             if (idx == -1)
  659.             {
  660.                 if (tabModifiers == 0)
  661.                 {
  662.                     doTab((Component) tabbed.lastElement(), tabModifiers);
  663.                 }
  664.                 else
  665.                 {
  666.                     doTab((Component) tabbed.firstElement(), tabModifiers);
  667.                 }
  668.  
  669.                 return true;
  670.             }
  671.             else
  672.             {
  673.                 int tabFromIdx = idx;
  674.  
  675.                 while (true)
  676.                 {
  677.                     if (tabModifiers == 0) // regular tab
  678.                     {
  679.                         if (++idx == sze)
  680.                         {
  681.                             idx = 0;
  682.                         }
  683.                     }
  684.                     else
  685.                     {
  686.                         if (--idx == -1)
  687.                         {
  688.                             idx = sze - 1;
  689.                         }
  690.                     }
  691.  
  692.                     if (tabFromIdx == idx)    // looped through all items and none were enabled
  693.                     {
  694.                         break;
  695.                     }
  696.  
  697.                     try
  698.                     {
  699.                         tabTo = (Component) tabbed.elementAt(idx);
  700.  
  701.                         if (tabTo.isEnabled() && tabTo.isVisible())
  702.                         {
  703.                             //Check if user wants to tab only to TextComponents
  704.                             if (!bOnlyTabToTextComponents || tabTo instanceof TextComponent)
  705.                             {
  706.                                 tabTo.requestFocus();
  707.     
  708.                                 if (tabTo instanceof TextComponent)
  709.                                 {
  710.                                     TextComponent tc = (TextComponent) tabTo;
  711.                                     tc.selectAll();
  712.                                 }
  713.     
  714.                                   Component tabFrom = (Component) tabbed.elementAt(iCurrent);
  715.                                    Event eLostFocus = new Event(tabFrom, Event.LOST_FOCUS, null);
  716.                                 tabFrom.postEvent(eLostFocus);
  717.     
  718.                                 if (tabFrom instanceof TextComponent)
  719.                                 {
  720.                                     TextComponent tf = (TextComponent) tabFrom;
  721.                                     tf.select(0,0);
  722.                                 }
  723.     
  724.                                    tabTo = (Component) tabbed.elementAt(idx);
  725.                                    Event eGotFocus = new Event(tabTo, Event.GOT_FOCUS, null);
  726.                                 tabTo.postEvent(eGotFocus);
  727.     
  728.                                 return true;
  729.                             }
  730.                         }
  731.                     }
  732.                     catch (ArrayIndexOutOfBoundsException e)
  733.                     {
  734.                     }
  735.                 }
  736.             }
  737.         }
  738.  
  739.         return false;
  740.     }
  741. }
  742.